export interface PacketSplitterOptions {
  chunkSize?: number; // 分片大小（字节）
  maxRetries?: number; // 分片发送失败重试次数
  timeout?: number; // 单分片超时时间(ms)
}


type TransferDataFnParams = {
  packetSequence: number;
  data: Uint8Array;
  dataLength: number;
  isLastChunk: boolean;
};
export type TransferDataFn = (params: TransferDataFnParams) => Promise<void>;

export class PacketSplitter {
  public config: Required<PacketSplitterOptions>;
  public receiveBuffer: {
    packets: Map<string, ArrayBuffer[]>; // deviceId -> packet[]
    timers: Map<string, any>; // 重组超时定时器
    expectedSequences: Map<string, number>; // 预期序列号
    errors: Map<string, string[]>; // 预期序列号
  };
  constructor(options: PacketSplitterOptions = {}) {
    // 配置参数
    this.config = {
      chunkSize: 128,
      maxRetries: 1,
      timeout: 3000,
      ...options
    };
    // 接收缓冲区
    this.receiveBuffer = {
      packets: new Map(), // deviceId -> packet[]
      timers: new Map(), // 重组超时定时器
      expectedSequences: new Map(), // 预期序列号
      errors: new Map() // 错误信息
    };
  }

  async send(data: Uint8Array, fn: TransferDataFn, packetSequenceStart = 0) {
    let sequence = packetSequenceStart;
    const len = data.length;
    for (let offset = 0; offset < len; offset += this.config.chunkSize) {
      const chunk = data.slice(offset, offset + this.config.chunkSize);
      await this._sendWithRetry(
        () =>
          fn({
            packetSequence: sequence,
            data: chunk,
            dataLength: chunk.length,
            isLastChunk: offset + this.config.chunkSize >= len
          }),
        sequence
      );
      sequence++;
    }
  }

  /**
   * 处理接收到的分片数据
   * @param {ArrayBuffer} data
   * @param {string} deviceId
   * @returns {ArrayBuffer|null} 完整数据包或null(未完成)
   */
  processReceivedPacket(
    packet: {
      sequence: number; // 包序列号 0x00～0xFF
      length: number; // 每次传输的有效数据长度 0x01～len  0x00 表示结束
      data: Uint8Array; // 数据内容 0x01～len  0x00 表示结束
    },
    deviceId: string,
    hasCrc = false
  ) {
    // 获取或初始化缓冲区
    let buffer = this._getOrCreateBuffer(deviceId);
    // 优先处理结束标志
    if (this._isEndPacket(packet)) {
      return this._handleEndPacket(buffer, deviceId);
    }
    // try {
    //   // 1. 参数校验
    //   // this._validatePacket(packet);
    //   // this._checkSequence(packet.sequence, deviceId);
    // } catch (error: any) {
    //   this.receiveBuffer.errors.get(deviceId)?.push(error.message || 'Unknown error');
    //   return null;
    // }
    if (hasCrc) {
      //@ts-ignore
      buffer[packet.sequence] = packet.data.subarray(2);
    } else {
      //@ts-ignore
      buffer[packet.sequence] = packet.data.buffer;
    }

    this.receiveBuffer.expectedSequences.set(deviceId, packet.sequence + 1);
    return null;
  }

  private async _sendWithRetry(fn: () => Promise<void>, sequence: number) {
    let retryCount = 0;
    const { maxRetries, timeout } = this.config;
    try {
      // 设置超时控制
      const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => reject(new Error('发送超时')), timeout);
      });
      // 并行执行写入和超时监控
      await Promise.race([fn(), timeoutPromise]);
      return;
    } catch (err: any) {
      console.log(`分片 ${sequence} 发送失败: ${err.message}`);
      throw new Error(`分片 ${sequence} 发送失败: ${err.message}`);
    }
    // while (retryCount < maxRetries) {
    //   try {
    //     // 设置超时控制
    //     const timeoutPromise = new Promise((_, reject) => {
    //       setTimeout(() => reject(new Error('发送超时')), timeout);
    //     });
    //     // 并行执行写入和超时监控
    //     await Promise.race([fn(), timeoutPromise]);
    //     console.log(`分片 ${sequence} 发送成功`);
    //     return;
    //   } catch (err: any) {
    //     if (retryCount++ > maxRetries) {
    //       throw new Error(`分片 ${sequence} 发送失败: ${err.message}`);
    //     }
    //     console.warn(`分片 ${sequence} 第 ${retryCount} 次重试...`, err);
    //     await new Promise((resolve) => setTimeout(resolve, 100 * Math.pow(2, retryCount)));
    //   }
    // }
  }

  /**
   * 重组数据包
   */
  private _assemblePackets(packets: ArrayBuffer[]) {
    let totalSize = 0;
    for (let i = 0; i < packets.length; i++) {
      totalSize += packets[i].byteLength;
    }
    const result = new Uint8Array(totalSize);
    let offset = 0;
    for (let i = 0; i < packets.length; i++) {
      if (packets[i]) {
        const chunk = new Uint8Array(packets[i]);
        result.set(chunk, offset);
        offset += chunk.length;
      }
    }
    return result.buffer;
  }

  /**
   * 设置重组超时定时器
   */
  private _setReassemblyTimeout(deviceId: string) {
    this._clearTimeout(deviceId);
    const timer = setTimeout(() => {
      this.receiveBuffer.packets.delete(deviceId);
      this.receiveBuffer.expectedSequences.delete(deviceId);
      console.warn(`设备 ${deviceId} 数据包重组超时`);
    }, this.config.timeout * 3); // 超时时间是单分片的3倍
    this.receiveBuffer.timers.set(deviceId, timer);
  }

  private _clearDeviceBuffer(deviceId: string): void {
    this.receiveBuffer.packets.delete(deviceId);
    this.receiveBuffer.expectedSequences.delete(deviceId);
    this._clearTimeout(deviceId);
  }

  private _clearTimeout(deviceId: any) {
    if (this.receiveBuffer.timers.has(deviceId)) {
      clearTimeout(this.receiveBuffer.timers.get(deviceId));
      this.receiveBuffer.timers.delete(deviceId);
    }
  }
  // 辅助方法
  private _validatePacket(packet: { sequence: number; length: number; data: Uint8Array }): void {
    if (packet.sequence < 0 || packet.sequence > 0xff) {
      throw new Error(`Invalid sequence number ${packet.sequence}`);
    }
    if (packet.length < 0 || packet.length > 0xff) {
      throw new Error(`Invalid length ${packet.length}`);
    }
    // 不校验长度 应
    // if (packet.data.length !== packet.length) {
    //   throw new Error(`Data length ${packet.data.length} does not match expected length ${packet.length}`);
    // }
  }

  private _isEndPacket(packet: { length: number; data: Uint8Array }): boolean {
    return packet.length === 0 && packet.data.length === 0;
  }

  private _getOrCreateBuffer(deviceId: string): ArrayBuffer[] {
    let buffer = this.receiveBuffer.packets.get(deviceId);
    if (!buffer) {
      buffer = [];
      this.receiveBuffer.packets.set(deviceId, buffer);
      this.receiveBuffer.expectedSequences.set(deviceId, 0);
      this.receiveBuffer.errors.set(deviceId, []);
      this._setReassemblyTimeout(deviceId);
    }
    return buffer;
  }
  private _checkSequence(sequence: number, deviceId: string): void {
    const expectedSeq = this.receiveBuffer.expectedSequences.get(deviceId) || 0;
    if (sequence !== expectedSeq) {
      throw new Error(`Out-of-order packet: expected ${expectedSeq}, got ${sequence}`);
    }
  }
  private _handleEndPacket(buffer: ArrayBuffer[], deviceId: string) {
    this._clearTimeout(deviceId);
    const result = this._assemblePackets(buffer);
    this._clearDeviceBuffer(deviceId);
    return {
      data: result,
      errors: this.receiveBuffer.errors.get(deviceId) || []
    };
  }
}

export function createPacketSplitter(options?: PacketSplitterOptions) {
  return new PacketSplitter(options);
}
